package com.github.shiqiyue.myadmin.config.security.authentication.provider;

import com.github.shiqiyue.myadmin.entity.SessionUser;
import com.github.shiqiyue.myadmin.entity.system.Menu;
import com.github.shiqiyue.myadmin.service.system.rolemenu.RoleMenuService;
import com.github.shiqiyue.myadmin.service.system.user.UserService;
import com.github.shiqiyue.myadmin.util.json.JsonUtils;
import com.github.shiqiyue.myadmin.util.security.SecurityUtils;
import com.github.shiqiyue.myadmin.util.spring.HttpContextUtils;
import com.github.shiqiyue.myadmin.util.web.IpUtils;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/***
 * 管理员安全认证
 *
 * @author wwy
 *
 */
public class AdminAuthenticationProvider implements AuthenticationProvider {

    private final UserDetailsService userDetailsService;

    private final PasswordEncoder passwordEncoder;

    private RoleMenuService roleMenuService;

    public AdminAuthenticationProvider(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
        this.userDetailsService = userDetailsService;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
        UserService userService = (UserService) userDetailsService;
        String username = token.getName();
        // 从数据库找到的用户
        SessionUser sessionUser = null;
        if (username != null) {
            sessionUser = (SessionUser) userService.loadUserByUsername(username);
        }
        if (sessionUser == null || sessionUser.getUser() == null) {
            throw new UsernameNotFoundException("用户名或者密码错误");
        } else if (!sessionUser.isEnabled()) {
            throw new DisabledException("用户已被禁用");
        } else if (!sessionUser.isAccountNonExpired()) {
            throw new AccountExpiredException("账号已过期");
        } else if (!sessionUser.isAccountNonLocked()) {
            throw new LockedException("账号已被锁定");
        } else if (!sessionUser.isCredentialsNonExpired()) {
            throw new LockedException("登录凭证已过期");
        }
        // 数据库用户的密码
        String password = sessionUser.getPassword();
        // 与authentication里面的credentials相比较
        if (!passwordEncoder.matches(token.getCredentials().toString(),
                password)) {
            throw new BadCredentialsException("用户名或者密码错误");
        }
        // 登录成功
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        userService.updateLastLogin(sessionUser.getUser().getId(), IpUtils.getIpAddr(request));
        sessionUser.setLoginInfoHash(SecurityUtils.getLoginInfoHash(request));
        //获取权限
        sessionUser.setAuthorities(userService.getAuthoritiesByUser(sessionUser.getUser()));
        List<Menu> menuList = roleMenuService.selectAuthMenuByRoleId(sessionUser.getUser().getRoleId(),
                sessionUser.getUser().getHasAllAuthority());
        sessionUser.setMenuListJson(JsonUtils.beanToString(menuList));
        return new UsernamePasswordAuthenticationToken(sessionUser, password, sessionUser.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> authentication) {
        // 返回true后才会执行上面的authenticate方法,这步能确保authentication能正确转换类型
        return UsernamePasswordAuthenticationToken.class.equals(authentication);
    }


    public void setRoleMenuService(RoleMenuService roleMenuService) {
        this.roleMenuService = roleMenuService;
    }
}